import dayjs, { Dayjs } from 'dayjs';
import { FULL_DATE_FORMAT } from './enum';

/**
 * @group 时间处理
 * 判断时间是否是00:00（午夜零点）
 *
 * @param date 需要检验的时间，支持字符串、Date对象或Dayjs对象
 * @returns 是否是 00:00
 *
 * @example
 * ```ts
 * is0000(dayjs('2025-01-01T00:00')) // true
 * is0000(dayjs('2025-01-01T08:00')) // false
 * is0000('2025-01-01T00:00:00') // true
 * is0000(new Date('2025-01-01T00:00:00')) // true
 * ```
 */
export function is0000(date: string | Date | Dayjs): boolean {
  const d = dayjs(date);
  if (!d.isValid()) return false;
  return d.hour() === 0 && d.minute() === 0;
}

/**
 * @group 时间处理
 * 判断时间是否是24:00（午夜24点）
 *
 * @param date 需要检验的时间，支持字符串、Date对象或Dayjs对象
 * @returns 是否是 24:00
 *
 * @example
 * ```ts
 * is2400('2025-01-01T24:00') // true
 * is2400('2025-01-01T00:00') // false
 * is2400(dayjs('2025-01-01T24:00')) // false（dayjs解析后变为00:00）
 * ```
 */
export function is2400(date: string | Date | Dayjs): boolean {
  // 如果是字符串，直接检查是否包含 24:00
  if (typeof date === 'string' && /24:00/.test(date)) {
    return true;
  }
  // dayjs 会将 24:00 解析为第二天的 00:00，所以对于非字符串类型无法准确判断
  // 这里返回 false，因为无法区分是 00:00 还是 24:00
  const d = dayjs(date);
  if (!d.isValid()) return false;
  return false;
}

/**
 * 将输入的时间字符串对齐到最近的指定分钟间隔
 * @param inputTime - 时间字符串，例如 '2025-06-29T23:59:00'
 * @param interval - 分钟间隔，必须是 [5, 10, 15, 30, 60] 中的一个
 * @returns 格式化后的时间字符串，如 '2025-06-30 00:15'
 */
export function mapToNearest15MinInterval(dateTime: string, interval: number = 15): string {
  const time = dayjs(dateTime);

  if (!time.isValid()) {
    throw new Error('Invalid date format');
  }

  // 四舍五入到最近的 interval 倍数
  const timestamp = time.unix(); // 获取秒级时间戳
  const secondsPerInterval = interval * 60;
  const roundedTimestamp = Math.round(timestamp / secondsPerInterval) * secondsPerInterval;
  const mappedDateTime = dayjs.unix(roundedTimestamp);
  // 构造新时间：从当天 00:00 开始加 roundedMinutes 分钟

  // 返回格式化后的字符串
  return mappedDateTime.format(FULL_DATE_FORMAT);
}

/**
 * 生成指定数量的小时字符串数组（默认 24 小时）
 *
 * @param count - 要生成的小时数，默认 24
 * @returns 小时字符串数组，如 ["00", "01", ..., "23"]
 */
export function generateHourOptions(count: number = 24): string[] {
  return Array.from({ length: count }, (_, i) => String(i).padStart(2, '0'));
}

/**
 * 生成带分钟粒度的时间选项（如每 30 分钟一个）
 * @param totalMinutesInDay - 分钟总数，默认 24 * 60
 * @param step - 分钟步长，默认 15（即每15分钟一个）
 * @returns 时间字符串数组，如 ["00:00", "00:30", "01:00", ...]
 */
export function generateTimeOptionsWithStep(
  totalMinutesInDay: number = 24 * 60,
  step: number = 15
): string[] {
  const result: string[] = [];
  for (let i = 0; i < totalMinutesInDay; i += step) {
    const hour = Math.floor(i / 60);
    const minute = i % 60;
    result.push(`${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`);
  }
  return result;
}

/**
 * 计算两个时间戳之间相差的自然日,每满 24 小时就算一天
 * @param timestamp1 时间戳1
 * @param timestamp2 时间戳2
 * @returns
 */
export function dayDifference(
  timestamp1: number | Date | Dayjs | string,
  timestamp2: number | Date | Dayjs | string
): number {
  const timeDifference = Math.abs(dayjs(timestamp1).valueOf() - dayjs(timestamp2).valueOf());
  return Math.floor(timeDifference / (1000 * 60 * 60 * 24));
}

/**
 * 计算两个日期时间之间的持续时间
 *
 * @param startDateTime 开始日期时间，格式为 时间戳、字符串、Date类型、Dayjs类型
 * @param endDateTime 结束日期时间，格式为 时间戳、字符串、Date类型、Dayjs类型
 * @returns 返回一个包含小时和分钟的对象，表示两个日期时间之间的持续时间
 */

export function calcDurationDate(
  startDateTime: number | Date | Dayjs | string,
  endDateTime: number | Date | Dayjs | string
): { hours: number; minutes: number } {
  const MILLISECONDS_PER_HOUR = 1000 * 60 * 60;
  const MILLISECONDS_PER_MINUTE = 1000 * 60;

  // 将日期时间字符串转换为 Date 对象
  const startDate = dayjs(startDateTime);
  const endDate = dayjs(endDateTime);

  // 非法时间，抛出错误
  if (!startDate.isValid() || !endDate.isValid()) {
    throw new Error('Invalid date format');
  }

  const timeDifference = Math.abs(endDate.valueOf() - startDate.valueOf());
  const hours = Math.floor(timeDifference / MILLISECONDS_PER_HOUR);
  const minutes = Math.floor((timeDifference % MILLISECONDS_PER_HOUR) / MILLISECONDS_PER_MINUTE);
  return { hours, minutes };
}

/**
 * 根据传入的时间间隔，生成从 00:00 到 24:00 的时间数组
 * @param intervalMinutes
 * @param {number} [intervalMinutes=15] - 时间间隔（分钟），默认为 15
 * @returns {string[]} 返回格式为 "HH:MM" 的时间字符串数组，包含从 00:00 到 24:00 的间隔时间点
 * @example
 * timeRangeForm24Hour(15); // ["00:00", "00:15", "00:30", ..., "23:45", "24:00"]
 * timeRangeForm24Hour(30); // ["00:00", "00:30", "01:00", ..., "23:30", "24:00"]
 * timeRangeForm24Hour(60); // ["00:00", "01:00", ..., "23:00", "24:00"]
 */
export function timeRangeForm24Hour(intervalMinutes: number = 15): string[] {
  // 参数校验
  if (intervalMinutes <= 0 || intervalMinutes > 60 || 60 % intervalMinutes !== 0) {
    throw new Error(
      'intervalMinutes must be a positive divisor of 60 (e.g., 1, 5, 10, 15, 20, 30, 60)'
    );
  }
  const timeArray: string[] = [];
  const HOURS_IN_DAY = 24;
  const MINUTES_IN_HOUR = 60;
  for (let hour = 0; hour < HOURS_IN_DAY; hour++) {
    for (let minute = 0; minute < MINUTES_IN_HOUR; minute += intervalMinutes) {
      const formattedHour = String(hour).padStart(2, '0');
      const formattedMinute = String(minute).padStart(2, '0');
      timeArray.push(`${formattedHour}:${formattedMinute}`);
    }
  }
  // 添加 24:00 作为结束时间
  timeArray.push('24:00');

  return timeArray;
}

/**
 * 将分钟数格式化为小时和分钟数
 *
 * @param totalMinutes 分钟数
 * @param hText 小时文本，默认 "h"
 * @param mText 分钟文本，默认 "m"
 * @returns 格式化后的时间字符串，格式为 "小时 小时 分钟" 或 "0 分钟"
 */
export function formatMinutesToHoursMinutes(totalMinutes: number, hText = 'h', mText = 'm') {
  if (!totalMinutes) return '0m';
  const absMinutes = Math.abs(totalMinutes);

  // 计算小时和分钟
  const hours = Math.floor(absMinutes / 60);
  const minutes = absMinutes % 60;

  return {
    hours: hours,
    minutes,
    // 默认返回格式化字符串，如 "1h50m"
    toString() {
      if (hours === 0 && minutes === 0) return '0m';
      const hourStr = hours > 0 ? `${hours}${hText}` : '';
      const minuteStr = minutes > 0 ? `${minutes}${mText}` : '';
      return [hourStr, minuteStr].filter(Boolean).join('');
    },
  };
}

/**
 * 将分钟数格式化成天时分
 * @param totalMinutes 分钟数
 * @returns
 */
export function minutesToDHCompact(totalMinutes: number, dText = 'd', hText = 'h', mText = 'm') {
  const absMinutes = Math.abs(totalMinutes);

  const days = Math.floor(absMinutes / 1440);
  const hours = Math.floor((absMinutes % 1440) / 60);
  const minutes = absMinutes % 60;

  const t = [];
  if (days > 0) t.push(`${days}${dText}`);
  if (hours > 0) t.push(`${hours}${hText}`);
  if (minutes > 0) t.push(`${minutes}${mText}`);

  return {
    days,
    hours,
    minutes,
    tStr: t.length > 0 ? t.join('') : 0,
  };
}

/**
 * 根据筛选的日期数组过滤数据源
 * @param originFilterDataList 需要过滤的数据源
 * @param filterDateList 过滤依据：日期数组
 * @param field 对应filterDateList中的数据的字段 默认infoDate
 * @returns
 */
export const filterDataByFilterDate = <T extends Record<string, any>>(
  originFilterDataList: Array<T>,
  filterDateList: string[],
  field: string = 'infoDate'
) => {
  // 短路返回：无数据或无筛选条件时直接返回原数组，避免不必要遍历
  if (!originFilterDataList || originFilterDataList.length === 0) return [];
  if (!filterDateList || filterDateList.length === 0) return originFilterDataList;

  // 使用 Set 优化查找，将 O(n*m) 降为 O(n)
  const dateSet = new Set(filterDateList);

  // 使用 Array.filter 过滤数据
  return originFilterDataList.filter((item: T) => {
    const val = item[field];
    return val != null && dateSet.has(val as unknown as string);
  });
};
